use std::sync::{Arc, Mutex};
use std::{collections::HashMap, net, thread};
use std::{
    io::{self, BufRead, Read, Write},
    time,
};

#[derive(Debug)]
struct Server {
    addr: String,
    counter: Arc<Mutex<i32>>,
}

impl Server {
    fn new(addr: &str) -> Server {
        Server {
            addr: addr.to_string(),
            counter: Arc::new(Mutex::new(0)),
        }
    }

    fn run(&self) -> io::Result<()> {
        let listener = net::TcpListener::bind(self.addr.as_str())?;

        for stream in listener.incoming() {
            let mut stream = stream?;
            let counter = self.counter.clone();

            thread::spawn(move || {
                if let Err(err) = handle3(&mut stream, counter) {
                    panic!(err);
                };
                println!("ok");
            });
        }

        Ok(())
    }

    async fn run_from_tokio(&self) -> io::Result<()> {
        let listener = tokio::net::TcpListener::bind(self.addr.as_str()).await?;

        loop {
            let (stream, _) = listener.accept().await?;
            let counter = self.counter.clone();

            // if let Err(err) = tokio_handle(&mut stream, counter).await {
            //     panic!(err);
            // };
            // println!("ok");

            tokio::spawn(async move {
                let mut stream = stream.into_std().unwrap();
                if let Err(err) = tokio_handle(&mut stream, counter).await {
                    panic!(err);
                };
                println!("ok");
            });
        }
    }
}

fn handle(mut stream: &net::TcpStream) -> io::Result<()> {
    let mut request = Vec::new();
    let mut buffer = [0; 10];

    loop {
        let size = stream.read(&mut buffer)?;
        // println!("read size:{}", size);

        if size > 0 {
            request.write(&buffer[..size])?;
        }

        if size < 10 {
            println!("read finished");
            break;
        }
    }

    let req = get_request(request)?;

    println!("request:{:?}", req);

    let response = "HTTP/1.1 200 OK\r\n\r\n";

    stream.write(response.as_bytes())?;
    stream.flush()?;

    Ok(())
}

fn handle2(mut stream: &net::TcpStream) -> io::Result<()> {
    let reader = io::BufReader::new(stream);
    let mut req = Request::new(reader);
    req.set_method().unwrap();
    req.set_header().unwrap();
    req.set_body().unwrap();

    println!("request:{:?}", req);

    let response =
        "HTTP/1.1 200 OK\r\n\"Content-Type\":\"application/json\"\r\n{\"counter\":0}\r\n";

    stream.write(response.as_bytes())?;
    stream.flush()?;

    Ok(())
}

fn handle3(mut stream: &net::TcpStream, counter: Arc<Mutex<i32>>) -> io::Result<()> {
    let reader = io::BufReader::new(stream);
    let mut req = Request::new(reader);
    req.set_method().unwrap();
    req.set_header().unwrap();
    req.set_body().unwrap();

    let mut counter = counter.lock().unwrap();
    *counter += 1;

    println!("request:{:?}, counter:{}", req, counter);

    let body = format!("{{\"counter\": {:?}}}", counter);
    let response = format!(
        "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: {}\r\n\r\n{}\r\n",
        body.len(),
        body
    );

    thread::sleep(time::Duration::from_secs(30));

    stream.write(response.as_bytes())?;
    stream.flush()?;

    Ok(())
}

async fn tokio_handle(mut stream: &net::TcpStream, counter: Arc<Mutex<i32>>) -> io::Result<()> {
    let reader = io::BufReader::new(stream);
    let mut req = Request::new(reader);
    req.set_method().unwrap();
    req.set_header().unwrap();
    req.set_body().unwrap();
    println!("request:{:?}", req);

    let mut body = String::from("DEMO");
    if let Some(size) = req.method.find("test") {
        let mut counter = counter.lock().unwrap();
        *counter += 1;

        println!("counter:{:?}", counter);

        body = format!("{{\"counter\": {:?}}}", counter);

        if size > 0 {
            thread::sleep(time::Duration::from_secs(30));
        }
    }

    let response = format!(
        "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: {}\r\n\r\n{}\r\n",
        body.len(),
        body
    );

    stream.write(response.as_bytes())?;
    stream.flush()?;

    Ok(())
}

#[derive(Debug)]
struct MyRequest {
    method: String,
    header: HashMap<String, String>,
    body: String,
}

#[derive(Debug)]
struct Request<'a> {
    method: String,
    header: HashMap<String, String>,
    body: String,
    reader: io::BufReader<&'a net::TcpStream>,
}

impl<'a> Request<'a> {
    fn new(reader: io::BufReader<&'a net::TcpStream>) -> Request<'a> {
        Request {
            method: String::new(),
            header: HashMap::new(),
            body: String::new(),
            reader: reader,
        }
    }

    fn set_method(&mut self) -> Result<(), String> {
        let mut buf = Vec::new();
        match self.reader.read_until(b'\n', &mut buf) {
            Err(err) => {
                return Err(format!(
                    "get method, read_until failed: {:?}",
                    err.to_string()
                ))
            }
            Ok(_) => {}
        };

        let method = match String::from_utf8(buf) {
            Ok(method) => method,
            Err(err) => {
                return Err(format!(
                    "get method, from_utf8 failed: {:?}",
                    err.to_string()
                ))
            }
        };

        self.method = method.trim_end_matches("\r\n").to_string();

        Ok(())
    }

    fn set_header(&mut self) -> Result<(), String> {
        let mut buf = String::new();
        loop {
            buf.clear();
            let size = match self.reader.read_line(&mut buf) {
                Ok(size) => size,
                Err(err) => {
                    return Err(format!(
                        "get method, from_utf8 failed: {:?}",
                        err.to_string()
                    ))
                }
            };
            println!("line:{:?}", buf);

            if size < 1 {
                continue;
            }

            if buf == "\r\n".to_string() {
                break;
            }

            let mut rows = buf.split(": ");
            let first = match rows.next() {
                Some(first) => first,
                None => "",
            };

            let second = match rows.next() {
                Some(second) => second,
                None => "",
            };

            let second = second.trim_end_matches("\r\n");

            self.header.insert(first.to_string(), second.to_string());
        }

        Ok(())
    }

    fn set_body(&mut self) -> Result<(), String> {
        let len = match self.header.get("Content-Length") {
            Some(cl) => cl.parse::<usize>().unwrap(),
            None => 0,
        };

        if len < 1 {
            return Ok(());
        }

        let mut buf = [0; 10];
        loop {
            let size = match self.reader.read(&mut buf) {
                Ok(size) => size,
                Err(err) => {
                    return Err(format!(
                        "get method, from_utf8 failed: {:?}",
                        err.to_string()
                    ))
                }
            };

            if size > 0 {
                let sr = String::from_utf8_lossy(&buf[..]).to_string();
                self.body.push_str(&sr[0..size]);
            }

            if size < 10 {
                break;
            }
        }

        Ok(())
    }
}

fn get_request(src: Vec<u8>) -> io::Result<MyRequest> {
    let mut req = MyRequest {
        method: String::new(),
        header: HashMap::new(),
        body: String::new(),
    };

    let mut src = &src[..];
    src.read_line(&mut req.method)?;

    let mut next_body = false;
    for line in src.lines() {
        let line = line?;

        if line.len() < 1 {
            next_body = true;
            continue;
        }

        if next_body {
            req.body = line;
            continue;
        }

        let mut rows = line.split(": ");
        let first = match rows.next() {
            Some(first) => first,
            None => "",
        };

        let second = match rows.next() {
            Some(second) => second,
            None => "",
        };

        req.header.insert(first.to_string(), second.to_string());
    }

    Ok(req)
}

#[cfg(test)]
mod test {
    use crate::web;
    use std::net;
    use std::{sync::mpsc, thread};

    #[test]
    fn thread() {
        let (tx, rx) = mpsc::channel();

        thread::spawn(move || {
            let val = String::from("hi");
            tx.send(val).unwrap();
        });

        for v in rx.iter() {
            println!("recv:{}", v);
        }
    }

    #[test]
    fn server() {
        web::Server::new("127.0.0.1:8081").run().unwrap();
    }

    #[test]
    fn tokio_server() {
        tokio_main();
    }

    #[tokio::main]
    async fn tokio_main() {
        web::Server::new("127.0.0.1:8081")
            .run_from_tokio()
            .await
            .unwrap();
    }
}
